<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" />
    <style>
        body {
            margin: 0;
            background: #1e1e1e;
            color: #fafafa;
            font-family: sans-serif;
        }

        .toolbar {
            display: flex;
            gap: 0.5rem;
            padding: 0.75rem;
            background: #2d2d2d;
            align-items: center;
        }

        .toolbar input,
        .toolbar button {
            padding: 0.4rem 0.6rem;
            border-radius: 4px;
            border: 1px solid #555;
            background: #3a3a3a;
            color: #fafafa;
        }

        .toolbar button {
            cursor: pointer;
        }

        #terminal {
            height: calc(100vh - 60px);
        }
    </style>

    <div class="toolbar">
        <label>
            Node ID:
            <input type="number" id="nodeId" value="1" min="1" />
        </label>
        <button id="connect">Connect</button>
        <button id="disconnect" disabled>Disconnect</button>
        <span id="status">Disconnected</span>
    </div>
    <div id="terminal"></div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/9.0.6/signalr.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.min.js"></script>
    <script>
        (async function () {
            const Terminal = window.Terminal;
            const FitAddon = window.FitAddon.FitAddon;

            const term = new Terminal({
                convertEol: true,
                cursorBlink: true,
                fontSize: 13,
                theme: {
                    background: '#1e1e1e',
                },
            });
            const fitAddon = new FitAddon();
            term.loadAddon(fitAddon);
            term.open(document.getElementById('terminal'));
            fitAddon.fit();

            const statusEl = document.getElementById('status');
            const connectBtn = document.getElementById('connect');
            const disconnectBtn = document.getElementById('disconnect');

            const connection = new signalR.HubConnectionBuilder()
                .withUrl('/api/signalr')
                .withAutomaticReconnect()
                .build();

            connection.serverTimeoutInMilliseconds = 6000;
            connection.keepAliveIntervalInMilliseconds = 2000;

            connection.onreconnecting(() => {
                statusEl.textContent = 'Reconnecting...';
            });

            connection.onreconnected(() => {
                statusEl.textContent = 'Connected';
            });

            connection.onclose(() => {
                statusEl.textContent = 'Disconnected';
                connectBtn.disabled = false;
                disconnectBtn.disabled = true;
            });

            connection.on('sshData', (payload) => {
                term.write(payload);
            });

            connection.on('sshClosed', () => {
                term.writeln('\r\n[Session closed]');
                connectBtn.disabled = false;
                disconnectBtn.disabled = true;
            });

            term.onData(async (data) => {
                if (connection.state === signalR.HubConnectionState.Connected) {
                    try {
                        await connection.invoke('SendSshInput', data);
                    } catch (error) {
                        console.error('send data error', error);
                    }
                }
            });

            window.addEventListener('resize', () => {
                fitAddon.fit();
                if (connection.state === signalR.HubConnectionState.Connected) {
                    connection.invoke('ResizeSshSession', term.cols, term.rows).catch(console.error);
                }
            });

            connectBtn.addEventListener('click', async () => {
                const nodeId = parseInt(document.getElementById('nodeId').value, 10);
                if (!Number.isInteger(nodeId)) {
                    alert('Please provide a valid node id');
                    return;
                }
                try {
                    if (connection.state !== signalR.HubConnectionState.Connected) {
                        await connection.start();
                    }
                    await connection.invoke('StartSshSession', nodeId, term.cols, term.rows);
                    statusEl.textContent = 'Connected';
                    connectBtn.disabled = true;
                    disconnectBtn.disabled = false;
                } catch (error) {
                    console.error('connection error', error);
                    statusEl.textContent = 'Failed to connect';
                }
            });

            disconnectBtn.addEventListener('click', async () => {
                try {
                    await connection.invoke('StopSshSession');
                } catch (error) {
                    console.warn('stop session error', error);
                }
                if (connection.state === signalR.HubConnectionState.Connected) {
                    await connection.stop();
                }
                statusEl.textContent = 'Disconnected';
                connectBtn.disabled = false;
                disconnectBtn.disabled = true;
            });

            window.addEventListener('beforeunload', () => {
                if (connection.state === signalR.HubConnectionState.Connected) {
                    connection.stop();
                }
            });
        })();
    </script>
</body>

</html>